import routerMap from './router.map'
import Router from 'vue-router'
import deepMerge from 'deepmerge'//合并
import basicOptions from './config.async';// parseRoutes(a,b)函数返回的处理过的路由
import $store from '@/store'

/**
 * 
 * meta.icon	菜单图标，图标使用 ant-design-vue 图标库，对应 Icon 组件 的 type 属性
 * meta.invisible	是否不将此路由项渲染为菜单项，默认false；如设置为 true，则生成菜单时将忽略此路由
 * 
*/



//应用配置
let appOptions = {
  router: undefined,
  i18n: undefined,
  store: undefined
}

/**
 * 设置应用配置
 * @param options
 */
function setAppOptions(options) {
  const {router, store, i18n} = options
  appOptions.router = router
  appOptions.store = store
  appOptions.i18n = i18n
}

/**
 * 根据 路由配置 和 路由组件注册 解析路由
 * @param routesConfig 路由配置
 * @param routerMap 本地路由组件注册配置
 */
/**
 * 处理路由
 * 
*/
function parseRoutes(routesConfig, routerMap) {
  let routes = []
  routesConfig.forEach(item => {
    // 获取注册在 routerMap 中的 router，初始化 routeCfg
    let router = undefined, routeCfg = {}
    if (typeof item === 'string') {
      router = routerMap[item]
      routeCfg = { path: (router && router.path) || item, router: item }
    } else if (typeof item === 'object') {
      router = routerMap[item.router]
      routeCfg = item
    }

    if (!router) {
      // 找不到路由器${routeCfg.router}的注册，请提前注册。
      console.warn(`can't find register for router ${routeCfg.router}, please register it in advance.`)
      router = typeof item === 'string' ? {path: item, name: item} : item
    }
    // 从 router 和 routeCfg 解析路由
    const meta = {
      authority: router.authority,
      icon: router.icon,
      page: router.page,
      link: router.link,
      params: router.params,
      query: router.query,
      ...router.meta
    }
    const cfgMeta = {
      authority: routeCfg.authority,
      icon: routeCfg.icon,
      page: routeCfg.page,
      link: routeCfg.link,
      params: routeCfg.params,
      query: routeCfg.query,
      ...routeCfg.meta
    }
    // Object.keys(cfgMeta)返回属性名{'authority'，。。。。。}
    Object.keys(cfgMeta).forEach(key => {
      if (cfgMeta[key] === undefined || cfgMeta[key] === null || cfgMeta[key] === '') {
        delete cfgMeta[key]
      }
    })
    Object.assign(meta, cfgMeta)
    const route = {
      path: routeCfg.path || router.path || routeCfg.router,
      name: routeCfg.name || router.name,
      component: router.component,
      redirect: routeCfg.redirect || router.redirect,
      meta: {...meta, authority: meta.authority || '*'}
    }
    // meta.invisible	是否不将此路由项渲染为菜单项，默认false；如设置为 true，则生成菜单时将忽略此路由
    if (routeCfg.invisible || router.invisible) {
      route.meta.invisible = true;//生成菜单时忽略此路由
    }
    if (routeCfg.children && routeCfg.children.length > 0) {
      route.children = parseRoutes(routeCfg.children, routerMap)
    }
    routes.push(route)
  })
  console.log('routes----', routes)
  return routes
}

/**
 * 加载路由
 * @param routesConfig {RouteConfig[]} 路由配置
 */
function loadRoutes(routesConfig) {
  //兼容 0.6.1 以下版本
  /*************** 兼容 version < v0.6.1 *****************/
  // arguments: 参数合集
  // console.log('这里是argument-' ,arguments)//打印的是routesConfig
  if (arguments.length > 0) {
    const arg0 = arguments[0]
    if (arg0.router || arg0.i18n || arg0.store) {
      routesConfig = arguments[1]
      console.error('the usage of signature loadRoutes({router, store, i18n}, routesConfig) is out of date, please use the new signature: loadRoutes(routesConfig).')
      console.error('方法签名 loadRoutes({router, store, i18n}, routesConfig) 的用法已过时, 请使用新的方法签名 loadRoutes(routesConfig)。')
    }
  }
  /*************** 兼容 version < v0.6.1 *****************/

  // 应用配置
  const {router, store, i18n} = appOptions
  // 如果 routesConfig 有值，则更新到本地，否则从本地获取
  if (routesConfig) {
    $store.commit('setRoutesConfig', routesConfig)
  } else {
    routesConfig = $store.state.routesConfig
  }
  // 如果开启了异步路由，则加载异步路由配置
  // const asyncRoutes = true
  const asyncRoutes = $store.state.asyncRoutes
  if (asyncRoutes) {
    if (routesConfig && routesConfig.length > 0) {
      console.log('22222222222')
      const routes = parseRoutes(routesConfig, routerMap)
      const finalRoutes = mergeRoutes(basicOptions.routes, routes)
      formatRoutes(finalRoutes);//格式化路径，将不以‘/’开头的变成‘/’开头
      router.options = {...router.options, routes: finalRoutes}
      router.matcher = new Router({...router.options, routes:[]}).matcher
      router.addRoutes(finalRoutes)
    }
  }
  // 初始化Admin后台菜单数据
  const rootRoute = router.options.routes.find(item => item.path === '/')
  const menuRoutes = rootRoute && rootRoute.children
  if (menuRoutes) {
    $store.commit('setMenuData', menuRoutes)
  }
}



/**
 * 合并路由 (浅拷贝函数，同名属性会被覆盖)
 * @param target {Route[]}
 * @param source {Route[]}
 * @returns {Route[]}
 */
function mergeRoutes(target, source) {
  const routesMap = {}
  target.forEach(item => routesMap[item.path] = item)
  source.forEach(item => routesMap[item.path] = item)
  return Object.values(routesMap)
}



/**
 * 深度合并路由
 * @param target {Route[]}
 * @param source {Route[]}
 * @returns {Route[]}
 */
function deepMergeRoutes(target, source) {
  // 映射路由数组
  const mapRoutes = routes => {
    const routesMap = {}
    routes.forEach(item => {
      routesMap[item.path] = {
        ...item,
        children: item.children ? mapRoutes(item.children) : undefined
      }
    })
    return routesMap
  }
  const tarMap = mapRoutes(target)
  const srcMap = mapRoutes(source)

  // 合并路由
  const merge = deepMerge(tarMap, srcMap)

  // 转换为 routes 数组 （采用递归进行深拷贝）
  const parseRoutesMap = routesMap => {
    return Object.values(routesMap).map(item => {
      if (item.children) {
        item.children = parseRoutesMap(item.children)
      } else {
        delete item.children
      }
      return item
    })
  }
  return parseRoutesMap(merge)
}



/**
 * 格式化路由
 * @param routes 路由配置
 */

// 把配置项中path不以'/'开头的加上'/'
function formatRoutes(routes) {
  routes.forEach(route => {
    const { path } = route
    if (!path.startsWith('/') && path !== '*') {
      route.path = '/' + path
    }
    if(route.children) {
      formatRoutes(route.children)
    }
  })
  formatAuthority(routes)
}



/**
 * 格式化路由的权限配置
 * @param routes 路由
 * @param pAuthorities 父级路由权限配置集合
 */
//遍历各个路由配置项中是否在meta元数据中加了权限配置，若是没有则都加上permission：'*'
// formatAuthority(routes, pAuthorities = [])  如果调用的时候没有传pAuthorities， 那么pAuthorities就默认是空数组
function formatAuthority(routes, pAuthorities = []) {
  routes.forEach(route => {
    const meta = route.meta
    // defaultAuthority: 默认权限 
    const defaultAuthority = pAuthorities[pAuthorities.length - 1] || { permission: '*' }
    if (meta) {
      //权限
      let authority = {}
      if (!meta.authority) {
        authority = defaultAuthority
      }else if (typeof meta.authority === 'string') {
        authority.permission = meta.authority
      } else if (typeof meta.authority === 'object') {
        authority = meta.authority
        const {role} = authority
        if (typeof role === 'string') {
          authority.role = [role]
        }
        if (!authority.permission && !authority.role) {
          authority = defaultAuthority
        }
      }
      meta.authority = authority
    } else {
      const authority = defaultAuthority
      route.meta = { authority }//等价于 rote.meta.authority = authority
    }
    route.meta.pAuthorities = pAuthorities
    if (route.children) {
      formatAuthority(route.children, [...pAuthorities, route.meta.authority])
    }
  })
}




/**
 * 加载导航守卫
 * @param guards
 * @param options
 */
function loadGuards(guards, options) {
  const {beforeEach, afterEach} = guards
  const {router} = options
  beforeEach.forEach(guard => {
    if (guard && typeof guard === 'function') {
      router.beforeEach((to, from, next) => guard(to, from, next, options))
    }
  })
  // afterEach.forEach(guard => {
  //   if (guard && typeof guard === 'function') {
  //     router.afterEach((to, from) => guard(to, from, options))
  //   }
  // })
}

export {parseRoutes, loadRoutes, formatAuthority, loadGuards, deepMergeRoutes, formatRoutes, setAppOptions}
